
/***********************************************************************************************************************
**                                                    Includes                                                        **
***********************************************************************************************************************/
#include "Com.h"
#include "CanDriver.h"
#include "CanTp.h"
#include "Rte.h"

/***********************************************************************************************************************
**                                           Global Variable Definitions                                              **
***********************************************************************************************************************/


/***********************************************************************************************************************
**                                            Private Macro Definitions                                               **
***********************************************************************************************************************/
/*Pdu Tx buffer*/
#define COM_TX_BUFFER_LEN_ACAN      (1000u)
#define COM_TX_BUFFER_LEN_CHCAN     (200u)

/* timeout:1000ms unit:10ms */
#define COM_ICU_TIMEOUT             (100u)
/* timeout:500ms unit:10ms */
#define COM_TBOX_TIMEOUT            (50u)
/* timeout:5000ms unit:10ms */
#define COM_BCM_TIMEOUT             (500u)
/* timeout:500ms unit:10ms */
#define COM_INV_TIMEOUT             (50u)
/* timeout:10000ms unit:10ms */
#define COM_OBC_TIMEOUT             (1000u)

#define COM_ENABLE_INTERRUPT()      __asm ("CPSIE  I")
#define COM_DISABLE_INTERRUPT()     __asm ("CPSID  I")

/*diagnostic communication*/
#define COM_DIAG_PhyReq_ID          CANTP_DIAG_PhyReq_ID
#define COM_DIAG_Resp_ID            CANTP_DIAG_Resp_ID
#define COM_DIAG_FuncReq_ID         CANTP_DIAG_FuncReq_ID


/***********************************************************************************************************************
**                                            Private Type Definitions                                                **
***********************************************************************************************************************/
/*Rx message information type definition*/
typedef struct
{
    uint32 canId;
    boolean update;
    uint8 len;
    uint8 data[8];
} Com_PduInfoType;

/*Tx buffer type definition*/
typedef struct
{
    uint32 canId;
    uint8 len;
    uint8 data[8];
} Com_TxBufferType;

typedef struct
{
    uint8 head;
    uint8 tail;
} Com_TxBufferCtrlType;

/*message receive timeout and busoff info.*/
typedef enum
{
    MESSAGE_TIMEOUT_ICU = 0, 
    MESSAGE_TIMEOUT_TBOX,
    MESSAGE_TIMEOUT_BCM, 
    MESSAGE_TIMEOUT_INV, 
    MESSAGE_TIMEOUT_OBC, 
    MESSAGE_TIMEOUT_MAX
} Com_MsgTimeoutType;

typedef struct
{
    uint16 msgTimeoutCnt[MESSAGE_TIMEOUT_MAX];
    boolean msgTimeoutFlag[MESSAGE_TIMEOUT_MAX];
    uint8 busoffFlag[COM_CHANNEL_MAX];
} Com_ErrorCtrlType;

/*communicaiton control information type definition*/
typedef struct
{
    boolean channelTxEnable[COM_CHANNEL_MAX];
    boolean channelRxEnable[COM_CHANNEL_MAX];
    boolean channelIsIdle[COM_CHANNEL_MAX];
    boolean isDiagMsgTx;
} Com_CtrlInfoType;


/***********************************************************************************************************************
**                                           Private Variable Definitions                                             **
***********************************************************************************************************************/
/*ACAN Rx message*/
static Com_PduInfoType Com_ACAN_RxPdu_BMU_CMD = {0x209, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_TBOX_BJS_Time = {0x3B3, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_BCM_VehiclePwrStauts = {0x210, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_INV_Info1Stauts = {0x220, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_INV_Info2Stauts = {0x221, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_INV_ErrorStauts = {0x331, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_ICU_InfoStatus = {0x350, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
static Com_PduInfoType Com_ACAN_RxPdu_Para_Set_BMS = {0x309, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};//temp
//static Com_PduInfoType Com_ACAN_RxPdu_TBOX_InfoStauts = {0x3B1, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_TBOX_Key2BMS1 = {0x3A2, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_TBOX_Key2BMS2 = {0x3A3, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};

//static Com_PduInfoType Com_ACAN_RxPdu_NM_TBOX = {0x402, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_NM_BCM = {0x403, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_NM_ICU = {0x404, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_ACAN_RxPdu_NM_INV = {0x406, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
static Com_PduInfoType Com_ACAN_RxPdu_Chrger_CMC_Chrg = {0x1802F4C0, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
static Com_PduInfoType Com_ACAN_RxPdu_Chrger_CMC_Wake = {0x1801F4C0, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
/*CHCAN Rx message*/

//static Com_PduInfoType Com_CHCAN_RxPdu_CID = {0x1832F456, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CHM = {0x1826F456, FALSE, 3u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CRM = {0x1801F456, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CTS = {0x1807F456, FALSE, 7u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CML = {0x1808F456, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CRO = {0x100AF456, FALSE, 1u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CCS = {0x1812F456, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CST = {0x101AF456, FALSE, 4u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CSD = {0x181DF456, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_CEM = {0x081FF456, FALSE, 4u, {0, 0, 0, 0, 0, 0, 0, 0}};
//static Com_PduInfoType Com_CHCAN_RxPdu_TPCM = {0x1CECF456, FALSE, 8u, {0, 0, 0, 0, 0, 0, 0, 0}};

/*ACAN Tx buffer*/
static Com_TxBufferType Com_TxBuffer_ACAN[COM_TX_BUFFER_LEN_ACAN];
static Com_TxBufferCtrlType Com_TxBufferCtrl_ACAN = {0, 0};
/*CHCAN Tx buffer*/
//static Com_TxBufferType Com_TxBuffer_CHCAN[COM_TX_BUFFER_LEN_CHCAN];
//static Com_TxBufferCtrlType Com_TxBufferCtrl_CHCAN = {0, 0};

/*message error control*/
static Com_ErrorCtrlType Com_ErrorCtrl;

/*communicaiton control information*/
Com_CtrlInfoType Com_CtrlInfo;


/***********************************************************************************************************************
**                                           Private Function Declarations                                            **
***********************************************************************************************************************/
/* Polling sending message.Execute this function once, and one bus sends only one frame. */
static void Com_PollingSendMsg(uint8 comChannel);
/*Tx message callout function*/
static void Com_TxMsgCallout(uint8 comChannel, uint32 canId, uint8* canDataPtr);

/***********************************************************************************************************************
**                                            Global Function Definitions                                             **
***********************************************************************************************************************/
/*called by Task_Init*/
void Com_Init(void)
{
    /*message error control*/
    //Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_ICU] = COM_ICU_TIMEOUT;
    //Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_TBOX] = COM_TBOX_TIMEOUT;
    //Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_BCM] = COM_BCM_TIMEOUT;
    //Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_INV] = COM_INV_TIMEOUT;
    //Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_OBC] = COM_OBC_TIMEOUT;
    for (Com_MsgTimeoutType i = MESSAGE_TIMEOUT_ICU; i < MESSAGE_TIMEOUT_MAX; i++)
    {
        Com_ErrorCtrl.msgTimeoutFlag[i] = FALSE;
    }
    for (Com_ChannelType i = COM_CHANNEL_ACAN; i < COM_CHANNEL_MAX; i++)
    {
        Com_ErrorCtrl.busoffFlag[i] = FALSE;
    }
    
    /*communicaiton control information*/
    for (Com_ChannelType i = COM_CHANNEL_ACAN; i < COM_CHANNEL_MAX; i++)
    {
        Com_CtrlInfo.channelIsIdle[i] = TRUE;
        Com_CtrlInfo.channelRxEnable[i] = TRUE;
        Com_CtrlInfo.channelTxEnable[i] = TRUE;
    }
    Com_CtrlInfo.isDiagMsgTx = FALSE;
}

/*called by idle task*/
void Com_MainFunction(void)
{
    Com_PollingSendMsg(COM_CHANNEL_ACAN);
   // Com_PollingSendMsg(COM_CHANNEL_CHCAN);
}

/*read newest can message by can id.*/
uint8 Com_ReceiveCanData(Com_ChannelType comChannel, uint32 canId, uint8* canDataPtr, uint8* len)
{
    uint8* srcPtr = NULL_PTR;
    uint8 ret = FALSE;
    uint8 i;

    /*ACAN*/
    if (COM_CHANNEL_ACAN == comChannel)
    {
        if ((canId == Com_ACAN_RxPdu_BMU_CMD.canId) && (TRUE == Com_ACAN_RxPdu_BMU_CMD.update))
        {
            Com_ACAN_RxPdu_BMU_CMD.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_BMU_CMD.data;
            *len = Com_ACAN_RxPdu_BMU_CMD.len;
        }
        else if ((canId == Com_ACAN_RxPdu_Chrger_CMC_Chrg.canId) && (TRUE == Com_ACAN_RxPdu_Chrger_CMC_Chrg.update))
        {
            Com_ACAN_RxPdu_Chrger_CMC_Chrg.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_Chrger_CMC_Chrg.data;
            *len = Com_ACAN_RxPdu_Chrger_CMC_Chrg.len;
        }
        else if ((canId == Com_ACAN_RxPdu_Chrger_CMC_Wake.canId) && (TRUE == Com_ACAN_RxPdu_Chrger_CMC_Wake.update))
        {
            Com_ACAN_RxPdu_Chrger_CMC_Wake.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_Chrger_CMC_Wake.data;
            *len = Com_ACAN_RxPdu_Chrger_CMC_Wake.len;
        }
/*        else if ((canId == Com_ACAN_RxPdu_TBOX_Key2BMS1.canId) && (TRUE == Com_ACAN_RxPdu_TBOX_Key2BMS1.update))
        {
            Com_ACAN_RxPdu_TBOX_Key2BMS1.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_TBOX_Key2BMS1.data;
            *len = Com_ACAN_RxPdu_TBOX_Key2BMS1.len;
        }
        else if ((canId == Com_ACAN_RxPdu_TBOX_Key2BMS2.canId) && (TRUE == Com_ACAN_RxPdu_TBOX_Key2BMS2.update))
        {
            Com_ACAN_RxPdu_TBOX_Key2BMS2.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_TBOX_Key2BMS2.data;
            *len = Com_ACAN_RxPdu_TBOX_Key2BMS2.len;
        }
        else if ((canId == Com_ACAN_RxPdu_BCM_VehiclePwrStauts.canId) && (TRUE == Com_ACAN_RxPdu_BCM_VehiclePwrStauts.update))
        {
            Com_ACAN_RxPdu_BCM_VehiclePwrStauts.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_BCM_VehiclePwrStauts.data;
            *len = Com_ACAN_RxPdu_BCM_VehiclePwrStauts.len;
        }
        else if ((canId == Com_ACAN_RxPdu_INV_Info1Stauts.canId) && (TRUE == Com_ACAN_RxPdu_INV_Info1Stauts.update))
        {
            Com_ACAN_RxPdu_INV_Info1Stauts.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_INV_Info1Stauts.data;
            *len = Com_ACAN_RxPdu_INV_Info1Stauts.len;
        }
        else if ((canId == Com_ACAN_RxPdu_INV_Info2Stauts.canId) && (TRUE == Com_ACAN_RxPdu_INV_Info2Stauts.update))
        {
            Com_ACAN_RxPdu_INV_Info2Stauts.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_INV_Info2Stauts.data;
            *len = Com_ACAN_RxPdu_INV_Info2Stauts.len;
        }
        else if ((canId == Com_ACAN_RxPdu_INV_ErrorStauts.canId) && (TRUE == Com_ACAN_RxPdu_INV_ErrorStauts.update))
        {
            Com_ACAN_RxPdu_INV_ErrorStauts.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_INV_ErrorStauts.data;
            *len = Com_ACAN_RxPdu_INV_ErrorStauts.len;
        }
        else if ((canId == Com_ACAN_RxPdu_ICU_InfoStatus.canId) && (TRUE == Com_ACAN_RxPdu_ICU_InfoStatus.update))
        {
            Com_ACAN_RxPdu_ICU_InfoStatus.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_ICU_InfoStatus.data;
            *len = Com_ACAN_RxPdu_ICU_InfoStatus.len;
        }*/
        else if ((canId == Com_ACAN_RxPdu_Para_Set_BMS.canId) && (TRUE == Com_ACAN_RxPdu_Para_Set_BMS.update))
        {
            Com_ACAN_RxPdu_Para_Set_BMS.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_Para_Set_BMS.data;
            *len = Com_ACAN_RxPdu_Para_Set_BMS.len;
        }
 /*       else if ((canId == Com_ACAN_RxPdu_NM_TBOX.canId) && (TRUE == Com_ACAN_RxPdu_NM_TBOX.update))
        {
            Com_ACAN_RxPdu_NM_TBOX.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_NM_TBOX.data;
            *len = Com_ACAN_RxPdu_NM_TBOX.len;
        }
        else if ((canId == Com_ACAN_RxPdu_NM_BCM.canId) && (TRUE == Com_ACAN_RxPdu_NM_BCM.update))
        {
            Com_ACAN_RxPdu_NM_BCM.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_NM_BCM.data;
            *len = Com_ACAN_RxPdu_NM_BCM.len;
        }
        else if ((canId == Com_ACAN_RxPdu_NM_ICU.canId) && (TRUE == Com_ACAN_RxPdu_NM_ICU.update))
        {
            Com_ACAN_RxPdu_NM_ICU.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_NM_ICU.data;
            *len = Com_ACAN_RxPdu_NM_ICU.len;
        }
        else if ((canId == Com_ACAN_RxPdu_NM_INV.canId) && (TRUE == Com_ACAN_RxPdu_NM_INV.update))
        {
            Com_ACAN_RxPdu_NM_INV.update = FALSE; //clear new message flag
            srcPtr = Com_ACAN_RxPdu_NM_INV.data;
            *len = Com_ACAN_RxPdu_NM_INV.len;
        }*/
        else
        {
            /*do not support canId*/
        }
    }
    /*CHCAN*/
  /*  else if (COM_CHANNEL_CHCAN == comChannel)
    {
        if ((canId == Com_CHCAN_RxPdu_OBC_AC_ChargeState.canId) && (TRUE == Com_CHCAN_RxPdu_OBC_AC_ChargeState.update))
        {
            Com_CHCAN_RxPdu_OBC_AC_ChargeState.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_OBC_AC_ChargeState.data;
            *len = Com_CHCAN_RxPdu_OBC_AC_ChargeState.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CCH.canId) && (TRUE == Com_CHCAN_RxPdu_CCH.update))
        {
            Com_CHCAN_RxPdu_CCH.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CCH.data;
            *len = Com_CHCAN_RxPdu_CCH.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CID.canId) && (TRUE == Com_CHCAN_RxPdu_CID.update))
        {
            Com_CHCAN_RxPdu_CID.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CID.data;
            *len = Com_CHCAN_RxPdu_CID.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CHM.canId) && (TRUE == Com_CHCAN_RxPdu_CHM.update))
        {
            Com_CHCAN_RxPdu_CHM.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CHM.data;
            *len = Com_CHCAN_RxPdu_CHM.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CRM.canId) && (TRUE == Com_CHCAN_RxPdu_CRM.update))
        {
            Com_CHCAN_RxPdu_CRM.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CRM.data;
            *len = Com_CHCAN_RxPdu_CRM.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CTS.canId) && (TRUE == Com_CHCAN_RxPdu_CTS.update))
        {
            Com_CHCAN_RxPdu_CTS.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CTS.data;
            *len = Com_CHCAN_RxPdu_CTS.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CML.canId) && (TRUE == Com_CHCAN_RxPdu_CML.update))
        {
            Com_CHCAN_RxPdu_CML.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CML.data;
            *len = Com_CHCAN_RxPdu_CML.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CRO.canId) && (TRUE == Com_CHCAN_RxPdu_CRO.update))
        {
            Com_CHCAN_RxPdu_CRO.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CRO.data;
            *len = Com_CHCAN_RxPdu_CRO.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CCS.canId) && (TRUE == Com_CHCAN_RxPdu_CCS.update))
        {
            Com_CHCAN_RxPdu_CCS.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CCS.data;
            *len = Com_CHCAN_RxPdu_CCS.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CST.canId) && (TRUE == Com_CHCAN_RxPdu_CST.update))
        {
            Com_CHCAN_RxPdu_CST.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CST.data;
            *len = Com_CHCAN_RxPdu_CST.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CSD.canId) && (TRUE == Com_CHCAN_RxPdu_CSD.update))
        {
            Com_CHCAN_RxPdu_CSD.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CSD.data;
            *len = Com_CHCAN_RxPdu_CSD.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_CEM.canId) && (TRUE == Com_CHCAN_RxPdu_CEM.update))
        {
            Com_CHCAN_RxPdu_CEM.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_CEM.data;
            *len = Com_CHCAN_RxPdu_CEM.len;
        }
        else if ((canId == Com_CHCAN_RxPdu_TPCM.canId) && (TRUE == Com_CHCAN_RxPdu_TPCM.update))
        {
            Com_CHCAN_RxPdu_TPCM.update = FALSE; //clear new message flag
            srcPtr = Com_CHCAN_RxPdu_TPCM.data;
            *len = Com_CHCAN_RxPdu_TPCM.len;
        }
        else
        {
            /*do not support canId*/
//        }
 //   }
    else
    {
        /*do not support comChannel*/
    }
    
    /*copy data*/
    if (NULL_PTR != srcPtr)
    {
        for (i = 0; i < *len; i++)
        {
            canDataPtr[i] = srcPtr[i];
        }
        ret = TRUE;
    }
    
    return ret;
}


/*send a can message by FIFO.
 *Note: Non reentrant*/
void Com_SendCanData(Com_ChannelType comChannel, uint32 canId, uint8* canDataPtr, uint8 Len)
{
    Com_TxBufferType* ptr = NULL_PTR;
    uint8 i;

    /*entry critical area*/
    COM_DISABLE_INTERRUPT();
    
    /*ACAN*/
    if (COM_CHANNEL_ACAN == comChannel)
    {
        if (TRUE == Com_CtrlInfo.channelTxEnable[COM_CHANNEL_ACAN])
        {
            ptr = &(Com_TxBuffer_ACAN[Com_TxBufferCtrl_ACAN.tail]);
            /*copy data*/
            ptr->canId = canId;
            ptr->len = Len;
            for (i = 0; i < Len; i++)
            {
                ptr->data[i] = canDataPtr[i];
            }
            /*update buffer control info*/
            Com_TxBufferCtrl_ACAN.tail++;
            if (COM_TX_BUFFER_LEN_ACAN == Com_TxBufferCtrl_ACAN.tail)
            {
                Com_TxBufferCtrl_ACAN.tail = 0;
            }
        }
    }
    /*CHCAN*/
   /* else if (COM_CHANNEL_CHCAN == comChannel)
    {
        if (TRUE == Com_CtrlInfo.channelTxEnable[COM_CHANNEL_CHCAN])
        {
            ptr = &(Com_TxBuffer_CHCAN[Com_TxBufferCtrl_CHCAN.tail]);
            copy data
            ptr->canId = canId;
            ptr->len = Len;
            for (i = 0; i < Len; i++)
            {
                ptr->data[i] = canDataPtr[i];
            }
            update buffer control info
            Com_TxBufferCtrl_CHCAN.tail++;
            if (COM_TX_BUFFER_LEN_CHCAN == Com_TxBufferCtrl_CHCAN.tail)
            {
                Com_TxBufferCtrl_CHCAN.tail = 0;
            }
        }
    }*/
    else
    {
        /*do not support comChannel*/
    }
    
    /*quit critical area*/
    COM_ENABLE_INTERRUPT();
}

/*this function process Message Timeout and Set Timeout Flag.*/
void Com_MessageTimeout(void)
{
    for (Com_MsgTimeoutType i = MESSAGE_TIMEOUT_ICU; i < MESSAGE_TIMEOUT_MAX; i++)
    {
        if (Com_ErrorCtrl.msgTimeoutCnt[i] > 0)
        {
            Com_ErrorCtrl.msgTimeoutCnt[i]--;
        }
        else
        {
            Com_ErrorCtrl.msgTimeoutFlag[i] = TRUE;
        }
    }
}

/*this function Get ICU Timeout Flag.*/
boolean Com_GetICUMessageTimeoutFlag(void)
{
    return Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_ICU];
}

/*this function Get TBOX Timeout Flag.*/
boolean Com_GetTBOXMessageTimeoutFlag(void)
{
    return Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_TBOX];
}

/*this function Get BCM Timeout Flag.*/
boolean Com_GetBCMMessageTimeoutFlag(void)
{
    return Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_BCM];
}

/*this function Get INV Timeout Flag.*/
boolean Com_GetINVMessageTimeoutFlag(void)
{
    return Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_INV];
}

/*this function Get OBC Timeout Flag.*/
boolean Com_GetOBCMessageTimeoutFlag(void)
{
    return Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_OBC];
}

/*this function Get ACAN Busoff Flag.*/
boolean Com_GetACANBusoffFlag(void)
{
    return Com_ErrorCtrl.busoffFlag[COM_CHANNEL_ACAN];
}

/*this function Get CHCAN Busoff Flag.*/
boolean Com_GetCHCANBusoffFlag(void)
{
    return Com_ErrorCtrl.busoffFlag[COM_CHANNEL_CHCAN];
}

/*communication control*/
void Com_DisableTx(uint8 comChannel)
{
    Com_CtrlInfo.channelTxEnable[comChannel] = FALSE;
}

void Com_EnableTx(uint8 comChannel)
{
    Com_CtrlInfo.channelTxEnable[comChannel] = TRUE;
}

void Com_DisableRx(uint8 comChannel)
{
    Com_CtrlInfo.channelRxEnable[comChannel] = FALSE;
}

void Com_EnableRx(uint8 comChannel)
{
    Com_CtrlInfo.channelRxEnable[comChannel] = TRUE;
}






/*
 * Callback Function
 */
/*this function indicates a successful reception of a received CAN message.*/
void Com_RxIndication(Com_ChannelType comChannel, uint32 canId,uint8 Frame_Type, uint8 canDlc, uint8 const* canDataPtr)
{
    uint8* dstPtr = NULL_PTR;
    uint8 dataLen;
    uint8 i;
    
    if (COM_CHANNEL_ACAN == comChannel)
    {
        /*common Rx indication callback*/
        Rte_Com_RxMsgNotify(0, canId);
        
        /* diagnostic frame */
        if ((COM_DIAG_PhyReq_ID == canId) || (COM_DIAG_FuncReq_ID == canId))
        {
            CanTp_RxIndication(canId, canDlc, canDataPtr);
        }
        /* network management*/
        else if ((canId == Com_ACAN_RxPdu_BMU_CMD.canId) && (canDlc == Com_ACAN_RxPdu_BMU_CMD.len) && (Frame_Type==CAN_FF_STANDARD))
        {
            Com_ACAN_RxPdu_BMU_CMD.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_BMU_CMD.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_Chrger_CMC_Chrg.canId) && (canDlc == Com_ACAN_RxPdu_Chrger_CMC_Chrg.len) && (Frame_Type==CAN_FF_EXTENDED))
        {
            Com_ACAN_RxPdu_Chrger_CMC_Chrg.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_Chrger_CMC_Chrg.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_Chrger_CMC_Wake.canId) && (canDlc == Com_ACAN_RxPdu_Chrger_CMC_Wake.len) && (Frame_Type==CAN_FF_EXTENDED))
        {
            Com_ACAN_RxPdu_Chrger_CMC_Wake.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_Chrger_CMC_Wake.data;
            dataLen = canDlc;
        }
/*        else if ((canId == Com_ACAN_RxPdu_NM_INV.canId) && (canDlc == Com_ACAN_RxPdu_NM_INV.len))
        {
            Com_ACAN_RxPdu_NM_INV.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_NM_INV.data;
            dataLen = canDlc;
        }
        /* communicaiton frame 
        else if ((canId == Com_ACAN_RxPdu_BCM_InfoBackup.canId) && (canDlc == Com_ACAN_RxPdu_BCM_InfoBackup.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_BCM] = COM_BCM_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_BCM] = FALSE;
            Com_ACAN_RxPdu_BCM_InfoBackup.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_BCM_InfoBackup.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_TBOX_BJS_Time.canId) && (canDlc == Com_ACAN_RxPdu_TBOX_BJS_Time.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_TBOX] = COM_TBOX_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_TBOX] = FALSE;
            Com_ACAN_RxPdu_TBOX_BJS_Time.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_TBOX_BJS_Time.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_TBOX_InfoStauts.canId) && (canDlc == Com_ACAN_RxPdu_TBOX_InfoStauts.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_TBOX] = COM_TBOX_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_TBOX] = FALSE;
            Com_ACAN_RxPdu_TBOX_InfoStauts.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_TBOX_InfoStauts.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_TBOX_Key2BMS1.canId) && (canDlc == Com_ACAN_RxPdu_TBOX_Key2BMS1.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_TBOX] = COM_TBOX_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_TBOX] = FALSE;
            Com_ACAN_RxPdu_TBOX_Key2BMS1.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_TBOX_Key2BMS1.data;
            dataLen = canDlc;
        }
		else if ((canId == Com_ACAN_RxPdu_TBOX_Key2BMS2.canId) && (canDlc == Com_ACAN_RxPdu_TBOX_Key2BMS2.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_TBOX] = COM_TBOX_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_TBOX] = FALSE;
            Com_ACAN_RxPdu_TBOX_Key2BMS2.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_TBOX_Key2BMS2.data;
            dataLen = canDlc;
        }
		else if ((canId == Com_ACAN_RxPdu_BCM_VehiclePwrStauts.canId) && (canDlc == Com_ACAN_RxPdu_BCM_VehiclePwrStauts.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_BCM] = COM_TBOX_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_BCM] = FALSE;
            Com_ACAN_RxPdu_BCM_VehiclePwrStauts.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_BCM_VehiclePwrStauts.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_INV_Info1Stauts.canId) && (canDlc == Com_ACAN_RxPdu_INV_Info1Stauts.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_INV] = COM_INV_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_INV] = FALSE;
            Com_ACAN_RxPdu_INV_Info1Stauts.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_INV_Info1Stauts.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_INV_Info2Stauts.canId) && (canDlc == Com_ACAN_RxPdu_INV_Info2Stauts.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_INV] = COM_INV_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_INV] = FALSE;
            Com_ACAN_RxPdu_INV_Info2Stauts.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_INV_Info2Stauts.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_INV_ErrorStauts.canId) && (canDlc == Com_ACAN_RxPdu_INV_ErrorStauts.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_INV] = COM_INV_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_INV] = FALSE;
            Com_ACAN_RxPdu_INV_ErrorStauts.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_INV_ErrorStauts.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_ACAN_RxPdu_ICU_InfoStatus.canId) && (canDlc == Com_ACAN_RxPdu_ICU_InfoStatus.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_ICU] = COM_ICU_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_ICU] = FALSE;
            Com_ACAN_RxPdu_ICU_InfoStatus.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_ICU_InfoStatus.data;
            dataLen = canDlc;
        } */
        else if ((canId == Com_ACAN_RxPdu_Para_Set_BMS.canId) && (canDlc == Com_ACAN_RxPdu_Para_Set_BMS.len) && (Frame_Type==CAN_FF_STANDARD))
        {   //test
            Com_ACAN_RxPdu_Para_Set_BMS.update = TRUE;
            dstPtr = Com_ACAN_RxPdu_Para_Set_BMS.data;
            dataLen = canDlc;
        }
        else
        {
            /*do not support canId*/
        }
    }
   /* else if (COM_CHANNEL_CHCAN == comChannel)
    {
        /*common Rx indication callback
        Rte_Com_RxMsgNotify(1u, canId);
        
        /* communicaiton frame
        if ((canId == Com_CHCAN_RxPdu_OBC_AC_ChargeState.canId) && (canDlc == Com_CHCAN_RxPdu_OBC_AC_ChargeState.len))
        {
            Com_ErrorCtrl.msgTimeoutCnt[MESSAGE_TIMEOUT_OBC] = COM_OBC_TIMEOUT;
            Com_ErrorCtrl.msgTimeoutFlag[MESSAGE_TIMEOUT_OBC] = FALSE;
            Com_CHCAN_RxPdu_OBC_AC_ChargeState.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_OBC_AC_ChargeState.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CCH.canId) && (canDlc == Com_CHCAN_RxPdu_CCH.len))
        {
            Com_CHCAN_RxPdu_CCH.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CCH.data;
            dataLen = canDlc;
        }
		else if ((canId == Com_CHCAN_RxPdu_CID.canId) && (canDlc == Com_CHCAN_RxPdu_CID.len))
        {
            Com_CHCAN_RxPdu_CID.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CID.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CHM.canId) && (canDlc == Com_CHCAN_RxPdu_CHM.len))
        {
            Com_CHCAN_RxPdu_CHM.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CHM.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CRM.canId) && (canDlc == Com_CHCAN_RxPdu_CRM.len))
        {
            Com_CHCAN_RxPdu_CRM.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CRM.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CTS.canId) && (canDlc == Com_CHCAN_RxPdu_CTS.len))
        {
            Com_CHCAN_RxPdu_CTS.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CTS.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CML.canId) && (canDlc == Com_CHCAN_RxPdu_CML.len))
        {
            Com_CHCAN_RxPdu_CML.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CML.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CRO.canId) && (canDlc == Com_CHCAN_RxPdu_CRO.len))
        {
            Com_CHCAN_RxPdu_CRO.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CRO.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CCS.canId) && ((6u == canDlc) || (7u == canDlc) || (8u == canDlc)))
        {
            Com_CHCAN_RxPdu_CCS.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CCS.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CST.canId) && (canDlc == Com_CHCAN_RxPdu_CST.len))
        {
            Com_CHCAN_RxPdu_CST.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CST.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CSD.canId) && (canDlc == Com_CHCAN_RxPdu_CSD.len))
        {
            Com_CHCAN_RxPdu_CSD.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CSD.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_CEM.canId) && (canDlc == Com_CHCAN_RxPdu_CEM.len))
        {
            Com_CHCAN_RxPdu_CEM.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_CEM.data;
            dataLen = canDlc;
        }
        else if ((canId == Com_CHCAN_RxPdu_TPCM.canId) && (canDlc == Com_CHCAN_RxPdu_TPCM.len))
        {
            Com_CHCAN_RxPdu_TPCM.update = TRUE;
            dstPtr = Com_CHCAN_RxPdu_TPCM.data;
            dataLen = canDlc;
        }
        else
        {
            /*do not support can id
        }
    }*/
    else
    {
        /*do not support can bus*/
    }
    
    /*copy data*/
    if (NULL_PTR != dstPtr)
    {
        for (i = 0; i < dataLen; i++)
        {
            dstPtr[i] = canDataPtr[i];
        }
    }
}

/*this function indicates a can busoff*/
void Com_BusOffIndication(Com_ChannelType comChannel)
{
    if (COM_CHANNEL_ACAN == comChannel)
    {
        Com_ErrorCtrl.busoffFlag[COM_CHANNEL_ACAN] = TRUE;
        Rte_Com_BusOffNotify(0);
    }
    else if (COM_CHANNEL_CHCAN == comChannel)
    {
        Com_ErrorCtrl.busoffFlag[COM_CHANNEL_CHCAN] = TRUE;
        Rte_Com_BusOffNotify(1u);
    }
    else
    {
        /*do not support CanBus*/
    }
}


/*this function confirms a previously successful processed transmission of a CAN message.*/
void Com_TxConfirmation(Com_ChannelType comChannel)
{
    if (COM_CHANNEL_ACAN == comChannel)
    {
        Com_CtrlInfo.channelIsIdle[COM_CHANNEL_ACAN] = TRUE;
        Com_ErrorCtrl.busoffFlag[COM_CHANNEL_ACAN] = FALSE;
        
        /*diagnostic communication control, clear transmit flag.*/
        if (TRUE == Com_CtrlInfo.isDiagMsgTx)
        {
            CanTp_TxConfirmation();
            Com_CtrlInfo.isDiagMsgTx = FALSE;
        }
        else
        {
            /*do nothing*/
        }
    }
  /*  else if (COM_CHANNEL_CHCAN == comChannel)
    {
        Com_CtrlInfo.channelIsIdle[COM_CHANNEL_CHCAN] = TRUE;
        Com_ErrorCtrl.busoffFlag[COM_CHANNEL_ACAN] = FALSE;
    }*/
    else
    {
        /*do not support CanBus*/
    }
}

/***********************************************************************************************************************
**                                           Private Function Definitions                                             **
***********************************************************************************************************************/
/* Polling sending message.Execute this function once, and one bus sends only one frame. */
static void Com_PollingSendMsg(uint8 comChannel)
{
    Com_TxBufferType* ptr = NULL_PTR;
    
    /*entry critical area*/
    COM_DISABLE_INTERRUPT();
    
    if ((COM_CHANNEL_ACAN == comChannel) && (TRUE == Com_CtrlInfo.channelIsIdle[COM_CHANNEL_ACAN]))
    {
        if (Com_TxBufferCtrl_ACAN.head != Com_TxBufferCtrl_ACAN.tail)
        {
            Com_CtrlInfo.channelIsIdle[COM_CHANNEL_ACAN] = FALSE;
            ptr = &(Com_TxBuffer_ACAN[Com_TxBufferCtrl_ACAN.head]);
            /*callout function*/
            Com_TxMsgCallout(COM_CHANNEL_ACAN, ptr->canId, ptr->data);
            /*transmit message*/
            CanDriver_Transmit(CANDRIVER_BUS_ACAN, ptr->canId, ptr->len, ptr->data);
            /*update buffer control info*/
            Com_TxBufferCtrl_ACAN.head++;
            if (COM_TX_BUFFER_LEN_ACAN == Com_TxBufferCtrl_ACAN.head)
            {
                Com_TxBufferCtrl_ACAN.head = 0;
            }
            
            /*diagnostic communication controll, set transmit flag.*/
            if (COM_DIAG_Resp_ID == ptr->canId)
            {
                Com_CtrlInfo.isDiagMsgTx = TRUE;
            }
        }
    }
    
 /*   if ((COM_CHANNEL_CHCAN == comChannel) && (TRUE == Com_CtrlInfo.channelIsIdle[COM_CHANNEL_CHCAN]))
    {
        if (Com_TxBufferCtrl_CHCAN.head != Com_TxBufferCtrl_CHCAN.tail)
        {
            Com_CtrlInfo.channelIsIdle[COM_CHANNEL_CHCAN] = FALSE;
            ptr = &(Com_TxBuffer_CHCAN[Com_TxBufferCtrl_CHCAN.head]);
            /*callout function
            Com_TxMsgCallout(COM_CHANNEL_CHCAN, ptr->canId, ptr->data);
            /*transmit message
            CanDriver_Transmit(CANDRIVER_BUS_CHCAN, ptr->canId, ptr->len, ptr->data);
            /*update buffer control info
            Com_TxBufferCtrl_CHCAN.head++;
            if (COM_TX_BUFFER_LEN_CHCAN == Com_TxBufferCtrl_CHCAN.head)
            {
                Com_TxBufferCtrl_CHCAN.head = 0;
            }
        }
    }*/
    
    /*quit critical area*/
    COM_ENABLE_INTERRUPT();
}

/*Tx message callout function*/
static void Com_TxMsgCallout(uint8 comChannel, uint32 canId, uint8* canDataPtr)
{
    if (COM_CHANNEL_ACAN == comChannel)
    {
        if (0x201 == canId)
        {
            //TODO:checksum
        }
    }
}

/***********************************************************************************************************************
**                                                  General Notes                                                     **
***********************************************************************************************************************/

